package io.geekidea.boot.outbound.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.geekidea.boot.auth.util.LoginUtil;
import io.geekidea.boot.common.PageDto;
import io.geekidea.boot.framework.response.ApiResult;
import io.geekidea.boot.inventorychange.entity.StoreChange;
import io.geekidea.boot.inventorychange.service.StoreChangeService;
import io.geekidea.boot.materials.entity.Materials;
import io.geekidea.boot.materials.service.MaterialsService;
import io.geekidea.boot.outbound.dto.OutboundDto;
import io.geekidea.boot.outbound.dto.OutboundExcel;
import io.geekidea.boot.outbound.entity.Outbound;
import io.geekidea.boot.outbound.query.OutboundQuery;
import io.geekidea.boot.outbound.service.OutboundService;
import io.geekidea.boot.salesslip.dto.SalesslipDto;
import io.geekidea.boot.salesslip.entity.Salesslip;
import io.geekidea.boot.store.entity.Store;
import io.geekidea.boot.store.service.StoreService;
import io.geekidea.boot.warehousentry.dto.WarehousentryDto;
import io.geekidea.boot.warehousentry.dto.WarehousentryExcel;
import io.geekidea.boot.warehousentry.query.WarehousentryQuery;
import io.geekidea.boot.warehousentry.query.entity.Warehousentry;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.ml.neuralnet.UpdateAction;
import org.checkerframework.checker.units.qual.N;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/outbound")
@Tag(name="出库单管理")
public class OutboundController {
    @Resource
    private OutboundService outboundService;
    @Resource
    private StoreService storeService;
    @Resource
    private MaterialsService materialsService;
    @Resource
    private StoreChangeService storeChangeService;
    @PostMapping("/search")
    @Operation(summary = "搜索出库单",description = "按照多条件组合分页查询出库单数据列表")
    public ApiResult search(@RequestBody OutboundQuery outboundQuery){
        Page<Outbound> page=new Page<>(outboundQuery.getPage(),outboundQuery.getSize());
        Page<Outbound> pageDto=outboundService.getOutboundPageList(page,outboundQuery);
        PageDto<Outbound> pageInfo=new PageDto<>(pageDto.getRecords(),pageDto.getTotal(),pageDto.getSize(),pageDto.getCurrent());
        return ApiResult.success(pageInfo);
    }



    @GetMapping("/get/{id}")
    @Operation(summary = "根据ID查询单条数据")
    public ApiResult getOutboundById(@PathVariable(value = "id")Integer id){
        final Outbound outbound=outboundService.getById(id);
        return ApiResult.success(outbound);
    }

    @DeleteMapping("/romove/{id}")
    @Operation(summary = "逻辑删除出库单")
    public ApiResult removeArea(@PathVariable(value = "id")Integer id){
        outboundService.removeById(id);
        return ApiResult.success("删除出库单数据成功！");
    }


    @PostMapping("/add")
    @Operation(summary = "添加出库单")
    public ApiResult addSalesslip(@RequestBody OutboundDto outboundDto) throws Exception {
        outboundDto.setOutboundTime(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        outboundDto.setCreatedTime(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        outboundDto.setCreatorUser(LoginUtil.getUsername());
        outboundDto.setCreatedBy(LoginUtil.getUsername());
        outboundDto.setCreatorUser(LoginUtil.getUsername());
        Outbound outboundEntity = new Outbound();
        BeanUtil.copyProperties(outboundDto,outboundEntity);
        outboundService.save(outboundEntity);
        //计算门店物料库存数据
        calculateInventory(outboundDto.getMaterialDetails(),outboundDto);
        return ApiResult.success("添加出库单数据成功！");
    }

    public void calculateInventory(String materialDetails,OutboundDto outboundDto) throws Exception {
        //解析物料json字符串转json
        JSONArray jsonArray = new JSONArray(materialDetails);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObj = jsonArray.getJSONObject(i);
            //物料名称
            String name = jsonObj.getObj("name").toString();
            if (!name.equals("")&&!name.equals(null)){
                //门店物料库id
                Integer wlId = Integer.parseInt(jsonObj.getObj("wlId").toString());
                //出库数量
                Integer xsNum =  Integer.parseInt(jsonObj.getObj("xsNum").toString());
                //总库存
                Integer totalStock =  Integer.parseInt(jsonObj.getObj("totalStock").toString());
                //门店可用库存数量
                Integer availableInventory =  Integer.parseInt(jsonObj.getObj("availableInventory").toString());
                //门店锁定全库存数量
                Integer lockInventory =  Integer.parseInt(jsonObj.getObj("lockInventory").toString());
                //计算门店剩余可用库存数量 = 门店可用库存数量 - 出库数量
//                Integer num =  availableInventory - xsNum;
                //计算新的锁定库存
                //Integer newXsNum =  lockInventory + xsNum;

                //修改库存数量
                Materials materialsEntity=new Materials();
                materialsEntity.setId(wlId);
                materialsEntity.setTotalStock(totalStock);
                //可用库存数量
                materialsEntity.setAvailableInventory(String.valueOf(availableInventory));
                //锁定库存数量
                materialsEntity.setLockInventory(String.valueOf(lockInventory));
                materialsService.updateById(materialsEntity);

                StoreChange storeChange = new StoreChange();
                storeChange.setWarehouseentrynumber(outboundDto.getOutbound());
                storeChange.setMaterialcode(jsonObj.getObj("code").toString());
                storeChange.setMaterialsnmark(jsonObj.getObj("taxsh").toString());
                storeChange.setNameofmaterial(jsonObj.getObj("name").toString());
                storeChange.setMaterialswarehouse(jsonObj.getObj("warehouseName").toString());
                storeChange.setTypeofchange(outboundDto.getType());
                storeChange.setChangebehavior(outboundDto.getBehaviorId());
                storeChange.setQuantityofchange(String.valueOf(xsNum));
                storeChange.setQuantityinstock(String.valueOf(totalStock));
                storeChange.setAvailablestock(String.valueOf(availableInventory));
                storeChange.setLockininventory(String.valueOf(lockInventory));
                storeChange.setTimeofchange(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                storeChange.setCreatedTime(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                storeChange.setCreatedBy(LoginUtil.getUsername());
                storeChange.setAreanameFk(outboundDto.getAreaId());
                storeChange.setStorenameFk(outboundDto.getStoresId());
                storeChangeService.save(storeChange);
            }

        }
    }


    @GetMapping("/del/{id}")
    @Operation(summary = "物理删除(取消)",description = "根据id物理删除(取消)对应的列")
    public ApiResult del(@PathVariable Integer id){
        int count = outboundService.delById(id);
        if (count<0) {
            return ApiResult.success("取消失败");
        }
        return ApiResult.success("取消成功");

    }


    @PostMapping("/update")
    public ApiResult updateArea(@Validated(value = {UpdateAction.class})@RequestBody OutboundDto outboundDto) throws Exception {
        //因为修改前需要取消之前的锁定库存和可用库存  再进行修改操作
        //查询该订单明细信息
        final Outbound outbound=outboundService.getById(outboundDto.getId());
        //解析物料json字符串转json
        JSONArray jsonArray = new JSONArray(outbound.getMaterialDetails());
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObj = jsonArray.getJSONObject(i);
            //物料名称
            String name = jsonObj.getObj("name").toString();
            if (!name.equals("")&&!name.equals(null)){
                //门店物料库id
                Integer wlId = Integer.parseInt(jsonObj.getObj("wlId").toString());
                //出库数量
                Integer xsNum =  Integer.parseInt(jsonObj.getObj("xsNum").toString());
                //总库存
                Integer totalStock =  Integer.parseInt(jsonObj.getObj("totalStock").toString());
                //门店可用库存数量
                Integer availableInventory =  Integer.parseInt(jsonObj.getObj("availableInventory").toString());
                //门店锁定全库存数量
                Integer lockInventory =  Integer.parseInt(jsonObj.getObj("lockInventory").toString());
                //计算门店可用库存数量 = 门店可用库存数量 + 出库数量
                Integer num =  availableInventory + xsNum;
                //计算新的锁定库存
                Integer newXsNum =  lockInventory - xsNum;
                //修改库存数量
                Materials materialsEntity=new Materials();
                materialsEntity.setId(wlId);
                materialsEntity.setAvailableInventory(String.valueOf(num));
                materialsEntity.setTotalStock(totalStock);
                //锁定库存数量
                materialsEntity.setLockInventory(String.valueOf(newXsNum));
                materialsService.updateById(materialsEntity);

                StoreChange storeChange = new StoreChange();
                storeChange.setWarehouseentrynumber(outboundDto.getOutbound());
                storeChange.setMaterialcode(jsonObj.getObj("code").toString());
                storeChange.setMaterialsnmark(jsonObj.getObj("taxsh").toString());
                storeChange.setNameofmaterial(jsonObj.getObj("name").toString());
                storeChange.setMaterialswarehouse(jsonObj.getObj("warehouseName").toString());
                storeChange.setTypeofchange(outboundDto.getType());
                storeChange.setChangebehavior(outboundDto.getBehaviorId());
                storeChange.setQuantityofchange(String.valueOf(xsNum));
                storeChange.setQuantityinstock(String.valueOf(totalStock));
                storeChange.setAvailablestock(String.valueOf(num));
                storeChange.setLockininventory(String.valueOf(newXsNum));
                storeChange.setTimeofchange(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                storeChange.setCreatedTime(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                storeChange.setCreatedBy(LoginUtil.getUsername());
                storeChange.setAreanameFk(outboundDto.getAreaId());
                storeChange.setStorenameFk(outboundDto.getStoresId());
                storeChangeService.save(storeChange);

            }

        }
        outboundDto.setUpdatedTime(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        outboundDto.setUpdatedBy(LoginUtil.getUsername());
        outboundDto.setStatus("0");
        Outbound outboundEntity = new Outbound();
        BeanUtil.copyProperties(outboundDto,outboundEntity);
        outboundService.updateById(outboundEntity);
        //修改完成后需要对修改后的物料库存数据更改
        //计算门店物料库存数据
        calculateInventory(outboundDto.getMaterialDetails(),outboundDto);
        return ApiResult.success("更改出库单数据成功！");
    }


    @PostMapping("/getNumbers/{storeCode}")
    @Operation(summary = "生成出库单号",description = "根据门店编号生成出库单号")
    public ApiResult getNumbers(@PathVariable String storeCode ){
        Store store = storeService.getById(storeCode);
        String code = generateOrderNumber(store.getCode());
        return ApiResult.success("生成出库单号成功",code);
    }

    public String generateOrderNumber(String storeCode) {
        LocalDateTime now = LocalDateTime.now();
        String formattedDate = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        long sequenceNumber = new Date().getTime();
        return "ck_" + storeCode + "_" + formattedDate + "_" + sequenceNumber;
    }

    @PostMapping("/updateStatus")
    @Operation(summary = "审核出库单状态")
    public ApiResult updateStatus(@RequestBody OutboundDto outboundDto) throws Exception {
        Outbound outboundEntity = new Outbound();
        outboundEntity.setId(outboundDto.getId());
        outboundEntity.setExamineUser(LoginUtil.getUsername());
        outboundEntity.setStatus(outboundDto.getStatus());
        outboundService.updateById(outboundEntity);
        //3:审核完成  需要单独操作
        if (outboundDto.getStatus().equals("3")) {
            //查询该订单明细信息
            final Outbound outbound=outboundService.getById(outboundDto.getId());
            //解析物料json字符串转json
            JSONArray jsonArray = new JSONArray(outbound.getMaterialDetails());
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObj = jsonArray.getJSONObject(i);
                //物料名称
                String name = jsonObj.getObj("name").toString();
                if (!name.equals("")&&!name.equals(null)){
                    //门店物料库id
                    Integer wlId = Integer.parseInt(jsonObj.getObj("wlId").toString());
                    //出库数量
                    Integer xsNum =  Integer.parseInt(jsonObj.getObj("xsNum").toString());

                    Materials materials = materialsService.getById(wlId);

                    //计算门店库存剩余数量 = 门店库存数量 - 出库数量
                    Integer num =  materials.getTotalStock() - xsNum;
                    //计新锁定库存剩余数量 = 门店锁定全库存数量 - 出库数量
                    Integer newNum =  Integer.parseInt(materials.getLockInventory()) - xsNum;

                    //修改库存数量
                    Materials materialsEntity=new Materials();
                    materialsEntity.setId(wlId);
                    materialsEntity.setTotalStock(num);
                    materialsEntity.setLockInventory(String.valueOf(newNum));
                    materialsService.updateById(materialsEntity);

                }

            }
        }
        return ApiResult.success("审核成功！");
    }


    @PostMapping("/download")
    @Operation(tags = "Post",description = "下载文件")
    public void download(@RequestBody OutboundQuery outboundQuery, HttpServletResponse response){
        List<OutboundExcel> list = outboundService.getDownloadList(outboundQuery);
        OutputStream outputStream = null;
        try {
            response.setCharacterEncoding("UTF-8");
            String excelName = URLEncoder.encode("outboundentry_"+ LocalDateTime.now(), "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + excelName + ".xlsx");
            // 以字节流的形式输出响应正文
            outputStream = response.getOutputStream();
            try (ExcelWriter excelWriter = EasyExcel.write(outputStream, OutboundExcel.class).build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                excelWriter.write(list,writeSheet);
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

}
